package br.mikhas.container.annotation;

import java.lang.annotation.Annotation;

import br.mikhas.container.application.AbstractApplicationContext;
import br.mikhas.container.application.ApplicationContext;
import br.mikhas.util.Assert;

/**
 * {@link ApplicationContext} which is feeded with annotated resources.
 * 
 * @author Mikhail Domanoski
 * 
 */
public class AnnotatedApplicationContext extends AbstractApplicationContext {

	protected AnnotatedBeanProvider annotatedResourceProvider;

	/**
	 * Creates a new instance of {@link AnnotatedApplicationContext} and defines
	 * the back packages to be scanned for resources.
	 * 
	 * @param basePackage
	 */
	public AnnotatedApplicationContext(String... basePackages) {
		annotatedResourceProvider = new AnnotatedBeanProvider();
		annotatedResourceProvider.addScannedPackages(basePackages);

		this.addScannedStereotype(Resource.class);
		this.addDefinitionExtractor(new ScopedBeanDefinitionExtractor());

		this.setResourceProvider(annotatedResourceProvider);
	}

	/**
	 * Adds a new annotation stereotype to be scanned as a simple bean or
	 * resource
	 * 
	 * @param stereotype
	 *            An annotation which defines an stereotype
	 */
	public void addScannedStereotype(Class<? extends Annotation> stereotype) {
		annotatedResourceProvider.addScannedStereotype(stereotype);
	}

	/**
	 * Registers a new {@link AnnotationPostProcessor} to this
	 * {@link ApplicationContext}.
	 * 
	 * @param processor
	 *            A post-processor which will runs after bean creation
	 */
	public void registerAnnotationProcessor(AnnotationPostProcessor<?> processor) {
		Assert.notNull(processor);
		this.addScannedStereotype(processor.getResourceAnnotation());
		this.registerResourcePostProcessor(processor);
	}

	/**
	 * Adds a new extractor to garther information from bean class
	 * 
	 * @param extractor
	 */
	public void addDefinitionExtractor(ChainedDefinitionExtractor extractor) {
		annotatedResourceProvider.addDefinitionExtractor(extractor);
	}
}
